package main

import (
	"fmt"
	"math"
	"perceptron/correlation"
	parsedata "perceptron/parseData"
	"perceptron/perceptron/classifier"
	"slices"

	"gonum.org/v1/gonum/mat"
)

func main() {

	matrix, names, err := parsedata.ParseCSV("./../agaricus-lepiota.data")
	if err != nil {
		panic(err)
	}

	for {
		corr := correlation.CorrMatrix(matrix)
		correlation.PrintCorrMatrix(corr, names)
		correlation.CreateHeatMap(corr)

		fmt.Println("Хотите удалить параметр? (y/n)")

		var resp rune
		fmt.Scanf("%c", &resp)
		if resp != 'y' {
			break
		}

		fmt.Println("Корреляцию, больше которой надо удалить:")
		var delVal float64
		fmt.Scan(&delVal)
		fmt.Println(delVal)

		rows, cols := matrix.RawMatrix().Rows, matrix.RawMatrix().Cols

		delCols := make([]int, 0)

		for i := 0; i < rows; i++ {
			for j := i + 1; j < cols; j++ {
				if math.Abs(corr.At(i, j)) > delVal && !math.IsNaN(corr.At(i, j)) {
					if !slices.Contains(delCols, j) {
						delCols = append(delCols, j)
					}
					fmt.Println("del", j, math.Abs(corr.At(i, j)))
					break
				}
			}
		}

		fmt.Println("del rows", delCols)

		tmp := make([]float64, 0)
		tmpNames := make([]string, 0)

		for i := 0; i < rows; i++ {
			for j := 0; j < cols; j++ {
				if slices.Contains(delCols, j) { //j == column {
					continue
				}
				tmp = append(tmp, matrix.At(i, j))
				if i == 0 {
					tmpNames = append(tmpNames, names[j])
				}
			}
		}
		fmt.Println(len(delCols))
		matrix = mat.NewDense(rows, cols-len(delCols), tmp)
		names = tmpNames
	}

	X, y := denseToData(matrix)

	lLen := int(float64(len(y)) * 0.8)

	lX, ly, testX, testy := X[:lLen], y[:lLen], X[lLen:], y[lLen:]

	q := 0
	for i := range lX {
		if ly[i] == 1 {
			q++
		}
	}
	fmt.Println(q, "/", len(ly))

	perc := &classifier.Classifier{}
	err = perc.Init([]uint{20}, len(lX)*80, len(X[0]), 2, 0.1)
	if err != nil {
		panic(err)
	}
	perc.Fit(lX, ly)
	s := perc.Test(testX, testy, []string{"poison", "eated"})

	fmt.Println(s)

	//гиперболический тангенс от 5

	fmt.Println(perc.Run(testX[0]), testy[0])
	fmt.Println(perc.Run(testX[10]), testy[10])
	fmt.Println(perc.Run(testX[20]), testy[20])
	fmt.Println(perc.Run(testX[30]), testy[30])
	fmt.Println()
	fmt.Println(perc.Run(lX[2]), ly[2])
	fmt.Println(perc.Run(lX[3]), ly[3])
	fmt.Println(perc.Run(lX[4]), ly[4])
	fmt.Println(perc.Run(lX[5]), ly[5])

}

func denseToData(m *mat.Dense) ([][]float64, []float64) {
	X := make([][]float64, m.RawMatrix().Rows)
	y := make([]float64, 0)

	for i := 0; i < m.RawMatrix().Rows; i++ {
		X[i] = make([]float64, m.RawMatrix().Cols-1)
		y = append(y, m.At(i, 0))
		for j := 1; j < m.RawMatrix().Cols-1; j++ {
			X[i][j] = m.At(i, j)
		}
	}
	fmt.Println(y)
	return X, y
}
